import os
import shutil
import sys
from json import dumps

import qpageview
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QFileDialog, QMessageBox, QWidget, QGridLayout, QLabel, QLineEdit, \
    QPushButton, QHBoxLayout, QScrollArea

from kege_station_modules.labellink import LabelLink
from kege_station_modules.pageview import pageView


class MainWindow(QMainWindow):
    """
    Основное окно программы
    """

    def keyPressEvent(self, QKeyEvent):
        """
        Обработка нажатия F11 для переключения полноэкранного режима
        :param QKeyEvent:
        """
        if QKeyEvent.key() == Qt.Key_F11:
            if self.isFullScreen():
                self.showMaximized()
            else:
                self.showFullScreen()

    def save_task(self) -> None:
        """
        Вызов диалогового окна для сохранения файла к заданию в указанную папку
        """
        sender = self.sender()
        source = f'files/Задание {self.current_page + 1}/{sender.text()}'
        path = os.path.expanduser('~')
        res = QFileDialog.getExistingDirectory(
            self,
            f"Выберите папку для сохранения файла {sender.text()}",
            path
        )
        if res != '':
            shutil.copyfile(source, f'{res}/{sender.text()}')

    def set_current_page(self) -> None:
        """
        Действия при переходе к другому заданию - подсветка кнопок, отображение файлов
        """
        self.pagenumberlabel.setText(f'Задание {self.current_page + 1} из {self.number_of_tasks}')
        self.answer_label.setText(f'Ответ на задание {self.current_page + 1}:')
        self.answer_input_field.setText('' if self.answers[self.current_page + 1] is False else
                                        self.answers[self.current_page + 1])
        if self.current_page + 1 in self.files_dict:
            for i in reversed(range(self.link_layout.count())):
                self.link_layout.itemAt(i).widget().setParent(None)
            cnt = 0
            for file in self.files_dict[self.current_page + 1]:
                file_label = LabelLink(file.split('/')[-1])
                file_label.clicked.connect(self.save_task)
                file_label.adjustSize()
                self.link_layout.addWidget(file_label, 0, cnt)
                cnt += 1
            self.files_for_task_label.setText('Файлы к заданию:')
        else:
            for i in reversed(range(self.link_layout.count())):
                self.link_layout.itemAt(i).widget().setParent(None)
            self.files_for_task_label.setText('')
        self.hbar.setValue(int(self.hbar.maximum() * ((self.current_page) / (self.number_of_tasks - 1))))
        for i in range(self.number_of_tasks):
            if not self.answers[i + 1]:
                self.buttons_numbers[i].setStyleSheet('')
            else:
                self.buttons_numbers[i].setStyleSheet('background-color: #00CF00')
        if self.answers[self.current_page + 1]:
            self.buttons_numbers[self.current_page].setStyleSheet(
                'height: 30px; border: 2px solid blue; background-color: #00CF00')
        else:
            self.buttons_numbers[self.current_page].setStyleSheet(
                'height: 30px; border: 2px solid blue')

    def next_page(self) -> None:
        """
        Переход к следующему заданию
        """
        if self.current_page < self.number_of_tasks - 1 and self.confirm_changing_page():
            self.v.gotoNextPage()
            self.current_page += 1
            self.set_current_page()

    def prev_page(self) -> None:
        """
        Переход к предыдущему заданию
        """
        if self.current_page > 0 and self.confirm_changing_page():
            self.v.gotoPreviousPage()
            self.current_page -= 1
            self.set_current_page()

    def goto_page_by_number(self, page_number: int) -> None:
        """
        Переход к заданию с указанным номером по кнопке
        :param page_number: int
        """
        if self.confirm_changing_page():
            self.current_page = page_number - 1
            self.v.setCurrentPageNumber(page_number)
            self.set_current_page()

    def confirm_changing_page(self) -> bool:
        """
        Вызывает окно подтверждения перехода к новому вопросу, если ответ на текущий введён, но не сохранён
        :return: bool
        """
        if (self.answers[self.current_page + 1]
            and self.answers[self.current_page + 1] == self.answer_input_field.text()) \
                or self.answer_input_field.text().strip() == '':
            return True
        dlg = QMessageBox(self)
        dlg.setIcon(QMessageBox.Warning)
        dlg.setWindowTitle("Внимание!")
        dlg.setText("Вы не сохранили ответ на вопрос!\nПодтверждаете переход к другому вопросу?")
        dlg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)

        if dlg.exec() == QMessageBox.Yes:
            return True
        return False

    def save_answer_function(self) -> None:
        """
        Функция сохранения ответа.
        Предусматривает невозможность ввода пустого ответа, сохраняет все попытки в лог
        """
        if self.answer_input_field.text().strip() != '':
            self.all_tries[self.current_page + 1].append(self.answer_input_field.text().strip())
            if not self.answers[self.current_page + 1]:
                self.solved_count += 1
            self.answers[self.current_page + 1] = self.answer_input_field.text().strip()
            self.buttons_numbers[self.current_page].setStyleSheet(
                'height: 30px; border: 2px solid blue; background-color: #00CF00')
            self.solved_cnt_label.setText(f'Дано ответов: {self.solved_count} из {self.number_of_tasks}')

    def get_files_for_tasks(self) -> dict:
        """
        Возвращает словарь, в котором каждому заданию по номеру соответсвует список приложенных к нему файлов
        :return: dict
        """
        ans = dict()
        folders_with_files = os.listdir('files')
        for folder in folders_with_files:
            task_number = int(folder.split()[-1])
            ans[task_number] = [f'files/{folder}/{i}' for i in os.listdir(f'files/{folder}')]
        return ans

    def exam_finish_function(self) -> bool:
        """
            Окно подтверждения завершения экзамена.
            Возвращает False, если нажата No
            :return: bool
        """
        alert_text = 'Вы собираетесь завершить экзамен.\nБыли получены следующие ответы:\n\n'
        for ans_number in range(len(self.answers)):
            if self.answers[ans_number + 1]:
                alert_text += f"{ans_number + 1}. {self.answers[ans_number + 1]}\n"
        alert_text += "\nЗавершить экзамен?"
        finish_exam_dlg = QMessageBox(
            QMessageBox.Warning,
            'Завершение экзамена',
            alert_text,
            QMessageBox.Ok | QMessageBox.Cancel
        )
        res = finish_exam_dlg.exec_()
        if res == QMessageBox.Ok:
            with open('exam_res.txt', 'w', encoding='utf-8') as file:
                file.write(dumps(self.answers, indent=4, ensure_ascii=False))
            with open('exam_log.txt', 'w', encoding='utf-8') as file:
                file.write(dumps(self.all_tries, indent=4, ensure_ascii=False))
            sys.exit()
        else:
            return False

    def closeEvent(self, QCloseEvent) -> None:
        """
        Обработка нажатия на крестик или закрытия с клавиатуры
        """
        if not self.exam_finish_function():
            QCloseEvent.ignore()

    def __init__(self):
        """
        Конструктор класса
        """
        QMainWindow.__init__(self)

        self.setWindowTitle("Станция записи ответов ЕГЭ по информатике")
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        grid_layout = QGridLayout()

        self.v = pageView()
        filename = 'task/kege-demo.pdf'
        if os.path.isfile(os.curdir + '/' + filename):
            doc = qpageview.loadPdf(filename)
        else:
            print('Нет встроенного в программу файла')
            try:
                filename = sys.argv[1]
                if filename.endswith('pdf'):
                    doc = qpageview.loadPdf(filename)
                else:
                    print('Некорректный файл')
                    sys.exit()
            except Exception as e:
                print(f'Не удалось открыть файл из параметра командной строки.\n{e}')
                sys.exit()
        self.v.setDocument(doc)
        self.v.setViewMode(qpageview.FitWidth)
        self.v.setContinuousMode(False)

        self.pages = self.v.pages()
        self.number_of_tasks = len(self.pages)
        self.current_page = 0

        self.answers = {num + 1: False for num in range(self.number_of_tasks)}
        self.all_tries = {num + 1: [] for num in range(self.number_of_tasks)}

        grid_layout.addWidget(self.v, 0, 0, 1, 3)

        self.files_dict = self.get_files_for_tasks()

        self.answer_label = QLabel('Ответ на задание 1:')
        grid_layout.addWidget(self.answer_label, 1, 0)
        self.answer_input_field = QLineEdit()
        grid_layout.addWidget(self.answer_input_field, 1, 1)
        save_button = QPushButton('Сохранить')
        save_button.clicked.connect(self.save_answer_function)
        grid_layout.addWidget(save_button, 1, 2)

        back = QPushButton('Назад')
        self.fwd = QPushButton('Вперёд')
        back.clicked.connect(self.prev_page)
        self.fwd.clicked.connect(self.next_page)
        grid_layout.addWidget(back, 2, 0)
        grid_layout.addWidget(self.fwd, 2, 2)
        scroll_layout = QHBoxLayout()
        self.buttons_numbers = []
        for i in range(self.number_of_tasks):
            button = QPushButton(f'{i + 1}')
            button.setFixedWidth(100)
            button.clicked.connect(lambda ch, page_number=i + 1: self.goto_page_by_number(page_number))
            self.buttons_numbers.append(button)
            scroll_layout.addWidget(button)
        self.buttons_numbers[0].setStyleSheet("height: 30px; border: 2px solid blue")
        scroll_widget = QWidget()
        scroll_widget.setLayout(scroll_layout)

        self.scroll_area = QScrollArea()
        self.scroll_area.setWidget(scroll_widget)
        self.scroll_area.setFixedHeight(70)
        grid_layout.addWidget(self.scroll_area, 2, 1)
        self.hbar = self.scroll_area.horizontalScrollBar()

        self.files_for_task_label = QLabel(f'')
        grid_layout.addWidget(self.files_for_task_label, 3, 0)

        self.link_to_files = QWidget()
        self.link_layout = QGridLayout()
        self.link_layout.setAlignment(Qt.AlignLeft)
        self.link_layout.setSpacing(30)
        self.link_to_files.setFixedHeight(40)
        self.link_to_files.setLayout(self.link_layout)
        grid_layout.addWidget(self.link_to_files, 3, 1)

        self.pagenumberlabel = QLabel(f'Страница 1 из {self.number_of_tasks}')
        grid_layout.addWidget(self.pagenumberlabel, 4, 0)

        self.solved_count = 0
        self.solved_cnt_label = QLabel(f'Дано ответов: 0 из {self.number_of_tasks}')
        grid_layout.addWidget(self.solved_cnt_label, 4, 1)

        self.finish_the_exam = QPushButton('Завершить экзамен')
        self.finish_the_exam.clicked.connect(self.exam_finish_function)
        grid_layout.addWidget(self.finish_the_exam, 4, 2)
        central_widget.setLayout(grid_layout)
        self.showMaximized()
